package com.yeskery.nut.extend.jdbc;

import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

/**
 * JDBC 操作模板
 * <span>query</span>系列方法只能处理基础数据类型，如果需要自动映射对象可使用<span>queryForObject</span>系列方法，
 * 并且提供<span>queryForMap</span>，将使用{@link java.sql.ResultSet#getObject(String)}自动将结果映射到{@link Map}中，
 * <span>queryForRow</span>系列方法，该方法和<span>queryForMap</span>系列方法一致，并提供一系列的自动转换基本类型的方法，
 * <span>queryForSteam</span>系列方法，将提供一系列将sql将结果集转换为{@link Stream}的方法
 * @author sprout
 * 2022-06-02 11:35
 */
public interface JdbcTemplate extends JdbcTransactionTemplate {

    /**
     * 执行SQL
     * @param callback 回调处理
     * @param <T> 回调类类型
     * @return 回调结果对象
     */
    <T> T execute(ConnectionCallback<T> callback);

    /**
     * 执行SQL
     * @param callback 回调处理
     * @param <T> 回调类类型
     * @return 回调结果对象
     */
    <T> T execute(StatementCallback<T> callback);

    /**
     * 执行SQL
     * @param callback 回调处理
     * @param sql sql
     * @param <T> 回调类类型
     * @return 回调结果对象
     */
    <T> T execute(String sql, PreparedStatementCallback<T> callback);

    /**
     * 执行SQL
     * @param sql sql
     * @return 影响的条数
     */
    default int execute(String sql) {
        return execute((StatementCallback<Integer>) stmt -> stmt.executeUpdate(sql));
    }

    /**
     * 批量执行SQL
     * @param sql sql
     * @return 批量影响的条数
     */
    default int[] batchExecute(String... sql) {
        return execute((StatementCallback<int[]>) stmt -> {
            for (String s : sql) {
                stmt.addBatch(s);
            }
            return stmt.executeBatch();
        });
    }

    /**
     * 批量执行SQL
     * @param sql sql
     * @param params 批量参数
     * @return 批量影响的条数
     */
    default int[] batchExecute(String sql, Object[][] params) {
        return execute(sql, pstmt -> {
            for (int i = 0; i < params.length; i++) {
                for (int j = 0; j < params[i].length; j++) {
                    pstmt.setObject(j + 1, params[i][j]);
                }
                pstmt.addBatch();
            }
            return pstmt.executeBatch();
        });
    }

    /**
     * 执行SQL
     * @param sql sql
     * @param params 参数
     * @return 影响的条数
     */
    default int execute(String sql, Object[] params) {
        return execute(sql, pstmt -> {
            for (int i = 0; i < params.length; i++) {
                pstmt.setObject(i + 1, params[i]);
            }
            return pstmt.executeUpdate();
        });
    }

    /**
     * 查询结果
     * @param sql sql
     * @param callback 回调处理
     * @param <T> 回调类类型
     * @return 查询结果
     */
    <T> T query(String sql, ResultSetRowCallback<T> callback);

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @param callback 回调处理
     * @param <T> 回调类类型
     * @return 查询结果
     */
    <T> T query(String sql, Object[] params, ResultSetRowCallback<T> callback);

    /**
     * 查询结果
     * @param sql sql
     * @param handler 处理器
     */
    void query(String sql, ResultSetHandler handler);

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @param handler 处理器
     */
    void query(String sql, Object[] params, ResultSetHandler handler);

    /**
     * 查询结果
     * @param sql sql
     * @param clazz 回调类型
     * @param <T> 回调类类型
     * @return 查询结果
     */
    <T> T query(String sql, Class<T> clazz);

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @param clazz 回调类型
     * @param <T> 回调类类型
     * @return 查询结果
     */
    <T> T query(String sql, Object[] params, Class<T> clazz);

    /**
     * 查询结果
     * @param sql sql
     * @param columnNameStrategy 列名策略
     * @param clazz 回调类型
     * @param <T> 回调类类型
     * @return 查询结果
     *
     * @see ColumnNameStrategies
     */
    <T> T queryForObject(String sql, ColumnNameStrategy columnNameStrategy, Class<T> clazz);

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @param columnNameStrategy 列名策略
     * @param clazz 回调类型
     * @param <T> 回调类类型
     * @return 查询结果
     *
     * @see ColumnNameStrategies
     */
    <T> T queryForObject(String sql, Object[] params, ColumnNameStrategy columnNameStrategy, Class<T> clazz);

    /**
     * 查询结果
     * @param sql sql
     * @param clazz 回调类型
     * @param <T> 回调类类型
     * @return 查询结果
     */
    default <T> T queryForObject(String sql, Class<T> clazz) {
        return queryForObject(sql, ColumnNameStrategies.camelToSnakeCase(), clazz);
    }

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @param clazz 回调类型
     * @param <T> 回调类类型
     * @return 查询结果
     */
    default <T> T queryForObject(String sql, Object[] params, Class<T> clazz) {
        return queryForObject(sql, params, ColumnNameStrategies.camelToSnakeCase(), clazz);
    }

    /**
     * 查询结果
     * @param sql sql
     * @param callback 回调处理
     * @param <T> 回调类类型
     * @return 查询结果
     */
    <T> List<T> queryForList(String sql, ResultSetRowCallback<T> callback);

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @param callback 回调处理
     * @param <T> 回调类类型
     * @return 查询结果
     */
    <T> List<T> queryForList(String sql, Object[] params, ResultSetRowCallback<T> callback);

    /**
     * 查询结果
     * @param sql sql
     * @param clazz 回调类
     * @param <T> 回调类类型
     * @return 查询结果
     */
    <T> List<T> queryForList(String sql, Class<T> clazz);

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @param clazz 回调类
     * @param <T> 回调类类型
     * @return 查询结果
     */
    <T> List<T> queryForList(String sql, Object[] params, Class<T> clazz);

    /**
     * 查询结果
     * @param sql sql
     * @param columnNameStrategy 列名策略
     * @param clazz 回调类
     * @param <T> 回调类类型
     * @return 查询结果
     *
     * @see ColumnNameStrategies
     */
    <T> List<T> queryForObjectList(String sql, ColumnNameStrategy columnNameStrategy, Class<T> clazz);

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @param columnNameStrategy 列名策略
     * @param clazz 回调类
     * @param <T> 回调类类型
     * @return 查询结果
     *
     * @see ColumnNameStrategies
     */
    <T> List<T> queryForObjectList(String sql, Object[] params, ColumnNameStrategy columnNameStrategy, Class<T> clazz);

    /**
     * 查询结果
     * @param sql sql
     * @param clazz 回调类
     * @param <T> 回调类类型
     * @return 查询结果
     */
    default <T> List<T> queryForObjectList(String sql, Class<T> clazz) {
        return queryForObjectList(sql, ColumnNameStrategies.camelToSnakeCase(), clazz);
    }

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @param clazz 回调类
     * @param <T> 回调类类型
     * @return 查询结果
     */
    default <T> List<T> queryForObjectList(String sql, Object[] params, Class<T> clazz) {
        return queryForObjectList(sql, params, ColumnNameStrategies.camelToSnakeCase(), clazz);
    }

    /**
     * 查询结果
     * @param sql sql
     * @return 查询结果
     */
    Map<String, Object> queryForMap(String sql);

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @return 查询结果
     */
    Map<String, Object> queryForMap(String sql, Object[] params);

    /**
     * 查询结果
     * @param sql sql
     * @return 查询结果
     */
    List<Map<String, Object>> queryForMapList(String sql);

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @return 查询结果
     */
    List<Map<String, Object>> queryForMapList(String sql, Object[] params);

    /**
     * 查询结果流
     * @param sql sql
     * @param columnNameStrategy 列名策略
     * @param clazz 回调类
     * @param <T> 回调类类型
     * @return 查询结果流
     */
    <T> Stream<T> queryForObjectStream(String sql, ColumnNameStrategy columnNameStrategy, Class<T> clazz);

    /**
     * 查询结果流
     * @param sql sql
     * @param params 参数
     * @param columnNameStrategy 列名策略
     * @param clazz 回调类
     * @param <T> 回调类类型
     * @return 查询结果流
     */
    <T> Stream<T> queryForObjectStream(String sql, Object[] params, ColumnNameStrategy columnNameStrategy, Class<T> clazz);

    /**
     * 查询结果流
     * @param sql sql
     * @param clazz 回调类
     * @param <T> 回调类类型
     * @return 查询结果流
     */
    default <T> Stream<T> queryForObjectStream(String sql, Class<T> clazz) {
        return queryForObjectStream(sql, ColumnNameStrategies.camelToSnakeCase(), clazz);
    }

    /**
     * 查询结果流
     * @param sql sql
     * @param params 参数
     * @param clazz 回调类
     * @param <T> 回调类类型
     * @return 查询结果流
     */
    default <T> Stream<T> queryForObjectStream(String sql, Object[] params, Class<T> clazz) {
        return queryForObjectStream(sql, params, ColumnNameStrategies.camelToSnakeCase(), clazz);
    }

    /**
     * 查询结果流
     * @param sql sql
     * @param clazz 回调类
     * @param <T> 回调类类型
     * @return 查询结果流
     */
    <T> Stream<T> queryForStream(String sql, Class<T> clazz);

    /**
     * 查询结果流
     * @param sql sql
     * @param params 参数
     * @param clazz 回调类
     * @param <T> 回调类类型
     * @return 查询结果流
     */
    <T> Stream<T> queryForStream(String sql, Object[] params, Class<T> clazz);

    /**
     * 查询结果流
     * @param sql sql
     * @param callback 回调处理
     * @param <T> 回调类类型
     * @return 查询结果流
     */
    <T> Stream<T> queryForStream(String sql, ResultSetRowCallback<T> callback);

    /**
     * 查询结果流
     * @param sql sql
     * @param params 参数
     * @param callback 回调处理
     * @param <T> 回调类类型
     * @return 查询结果流
     */
    <T> Stream<T> queryForStream(String sql, Object[] params, ResultSetRowCallback<T> callback);

    /**
     * 查询结果
     * @param sql sql
     * @return 查询结果
     */
    Row queryForRow(String sql);

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @return 查询结果
     */
    Row queryForRow(String sql, Object[] params);

    /**
     * 查询结果
     * @param sql sql
     * @return 查询结果
     */
    List<Row> queryForRowList(String sql);

    /**
     * 查询结果
     * @param sql sql
     * @param params 参数
     * @return 查询结果
     */
    List<Row> queryForRowList(String sql, Object[] params);

    /**
     * 获取SQL构建器
     * @return SQL构建器
     */
    JdbcSqlBuilder sqlBuilder();
}
